#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>

// 游戏信息结构体
struct Game {
    long mtype;  // 消息类型，必须放在第一位
    int Round;   // 出拳结果：0=石头, 1=剪刀, 2=布
};

// 发送出拳信息到消息队列
void result_send(int msg_id) {
    struct Game game;
    game.mtype = 1;                        // 设置消息类型
    game.Round = rand() % 3;               // 生成随机出拳(0-2)
    // 发送整个结构体，但不包括mtype字段
    if (msgsnd(msg_id, &game, sizeof(game.Round), 0) == -1) {
        perror("msgsnd failed");
        exit(EXIT_FAILURE);
    }
}

// 判断出拳结果
int result_announce(int a, int b) {
    if (a == b) return 0;                   // 平局
    if ((a == 0 && b == 1) ||               // 石头胜剪刀
        (a == 1 && b == 2) ||               // 剪刀胜布
        (a == 2 && b == 0))                 // 布胜石头
        return -1;                          // A胜
    return 1;                               // B胜
}

// 显示比赛结果
void displayResults(int *results, int rounds) {
    int wins_A = 0, wins_B = 0, draws = 0;
    
    for (int i = 0; i < rounds; i++) {
        switch(results[i]) {
            case -1: wins_A++; break;
            case 0: draws++; break;
            case 1: wins_B++; break;
        }
    }
    
    printf("\n=== 最终统计 ===\n");
    printf("A胜: %d次\nB胜: %d次\n平局: %d次\n", wins_A, wins_B, draws);
    printf("最终胜利者: %s\n", wins_A > wins_B ? "A" : wins_B > wins_A ? "B" : "平局");
}

int main() {
    int rounds;
    int *result_list;
    int msgid1, msgid2;
    pid_t pid1, pid2;
    
    srand(time(NULL));                      // 初始化随机数种子
    
    // 创建两个消息队列
    msgid1 = msgget(1234, IPC_CREAT | 0666);
    msgid2 = msgget(5678, IPC_CREAT | 0666);
    
    // 清空可能存在的旧消息
    struct Game temp;
    while (msgrcv(msgid1, &temp, sizeof(temp.Round), 0, IPC_NOWAIT) != -1) {}
    while (msgrcv(msgid2, &temp, sizeof(temp.Round), 0, IPC_NOWAIT) != -1) {}
    
    printf("请输入比赛轮数: ");
    scanf("%d", &rounds);
    
    result_list = malloc(rounds * sizeof(int));  // 分配结果数组内存
    
    for (int i = 0; i < rounds; i++) {
        // 创建选手A进程
        pid1 = fork();
        if (pid1 == 0) {
            srand(time(NULL) ^ getpid());   // 设置进程特有随机种子
            result_send(msgid1);            // 发送A的出拳
            exit(0);
        }
        
        // 创建选手B进程
        pid2 = fork();
        if (pid2 == 0) {
            srand(time(NULL) ^ getpid());   // 设置进程特有随机种子
            result_send(msgid2);            // 发送B的出拳
            exit(0);
        }
        
        // 等待两个选手进程完成
        waitpid(pid1, NULL, 0);
        waitpid(pid2, NULL, 0);
        
        struct Game a_choice, b_choice;
        // 接收A和B的出拳
        if (msgrcv(msgid1, &a_choice, sizeof(a_choice.Round), 1, 0) == -1) {
            perror("接收A出拳失败");
            continue;
        }
        if (msgrcv(msgid2, &b_choice, sizeof(b_choice.Round), 1, 0) == -1) {
            perror("接收B出拳失败");
            continue;
        }
        
        // 判断胜负并记录结果
        result_list[i] = result_announce(a_choice.Round, b_choice.Round);
        
        // 显示本轮结果
        char *choices[] = {"石头", "剪刀", "布"};
        printf("轮次%d: A出%s, B出%s -> %s\n", 
               i+1, 
               choices[a_choice.Round], 
               choices[b_choice.Round],
               result_list[i] == -1 ? "A胜" : result_list[i] == 0 ? "平局" : "B胜");
        
        // 刷新输出缓冲区，确保立即显示
        fflush(stdout);
    }
    
    displayResults(result_list, rounds);    // 显示最终结果
    
    free(result_list);                      // 释放内存
    msgctl(msgid1, IPC_RMID, 0);           // 删除消息队列
    msgctl(msgid2, IPC_RMID, 0);
    
    return 0;
}